import { ExtractJwt, Strategy } from 'passport-jwt';
import { PassportStrategy } from '@nestjs/passport';
import { Inject, Injectable, UnauthorizedException } from '@nestjs/common';
import { Cache } from 'cache-manager';
import { CACHE_MANAGER } from '@nestjs/cache-manager';
import { ConfigService } from '@nestjs/config';
import { getRedisKey } from 'src/utils';

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
  constructor(
    @Inject(CACHE_MANAGER) private cacheManager: Cache,
    private configService: ConfigService,
  ) {
    super({
      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
      ignoreExpiration: false,
      secretOrKey: configService.get('JWT_SECRET'),
    });
  }

  /*
        1. 对于 JWT 策略，Passport 首先验证 JWT 的签名并解码 JSON。然后调用我们的 validate() 方法，该方法将解码后的 JSON 作为其单个参数传递
        2. Passport 将基于 validate() 方法的返回值构建一个user 对象，并将其作为属性附加到请求对象上
            这种方法为我们留出了将其他业务逻辑注入流程的空间(就像"挂钩"一样)。例如，我们可以在 validate() 方法中执行数据库查询，以提取关于用户的更多信息，从而在请求中提供更丰富的用户对象
    */
  async validate(payload: any) {
    const { userId, ...rest } = payload; // token的解析内容
    // 从缓存中获取用户的权限
    const redisKey = getRedisKey(userId, 'user', 'info');
    const userInfo: any = await this.cacheManager.store.get(redisKey);
    const permissions = userInfo?.permissionInfo || []; // 权限，后续acl守卫使用

    if (!userInfo) throw new UnauthorizedException(`请重新登录`);

    return { userId, permissions };
  }
}
